package com.logistics.material.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.logistics.config.service.ConfigService;
import com.logistics.erp.entity.model.ErpInvBillSave;
import com.logistics.erp.service.ErpInvBillService;
import com.logistics.erp.service.ErpInvReqService;
import com.logistics.inventory.entity.domain.Inventory;
import com.logistics.inventory.entity.domain.InventoryDetail;
import com.logistics.inventory.service.InventoryDetailService;
import com.logistics.inventory.service.InventoryService;
import com.logistics.material.entity.domain.Material;
import com.logistics.material.entity.model.MaterialBackRow;
import com.logistics.material.entity.model.MaterialBackSave;
import com.logistics.material.entity.model.MaterialRow;
import com.logistics.material.mapper.MaterialMapper;
import com.logistics.pick.entity.domain.Pick;
import com.logistics.pick.entity.domain.PickContainer;
import com.logistics.pick.entity.domain.PickDetail;
import com.logistics.pick.entity.model.PickRow;
import com.logistics.pick.entity.model.PickSave;
import com.logistics.pick.service.PickContainerService;
import com.logistics.pick.service.PickDetailService;
import com.logistics.pick.service.PickService;
import com.logistics.qrcode.service.QrcodeService;
import com.logistics.utils.aspect.annotation.Insert;
import com.logistics.utils.bean.UserBean;
import com.logistics.utils.constants.Constants;
import com.logistics.utils.exception.MessageException;
import com.logistics.utils.tool.StringUtils;
import com.logistics.utils.tool.UserUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class MaterialService {

    @Autowired
    private MaterialMapper materialMapper;

    @Autowired
    private QrcodeService qrcodeService;

    @Autowired
    private ErpInvReqService erpInvReqService;

    @Autowired
    private MaterialPickService materialPickService;

    @Autowired
    private ErpInvBillService erpInvbillService;

    @Autowired
    private ConfigService configService;

    @Autowired
    private PickDetailService pickDetailService;

    @Autowired
    private InventoryDetailService inventoryDetailService;

    @Autowired
    private PickService pickService;

    @Autowired
    private PickContainerService pickContainerService;

    @Autowired
    private InventoryService inventoryService;

    @Autowired
    private UserUtils userUtils;

    /**
     * 查找物料列表根据托盘编号或者站点编码
     * @param code
     * @param pickStatus
     * @return
     */
    public List<MaterialRow> materials(String code, String pickStatus) throws MessageException {
        if (StringUtils.isNull(code)) {
            throw new MessageException("站点码/托盘码不可为空");
        }
        String point = qrcodeService.valueByCode(code, Constants.CODE_TYPE_LOCATION);
        if(StringUtils.isNull(point)) {
            throw new MessageException("站点不存在");
        }
        Map<String, Object> params = new HashMap<>();
        params.put("code", point);
        params.put("pickStatus", pickStatus);
        return materialMapper.finalMaterials(params).stream().
                map(MaterialRow::build).collect(Collectors.toList());
    }

    /**
     * 查找库存物料
     * @param code
     * @return
     * @throws MessageException
     */
    public List<MaterialRow> materials(String code) throws MessageException {
        if (StringUtils.isNull(code)) {
            throw new MessageException("站点码/托盘码不可为空");
        }
        String point = qrcodeService.valueByCode(code, Constants.CODE_TYPE_LOCATION);
        code = StringUtils.isNotNull(point) ? point : code;
        return materialMapper.findInventoryMaterials(code).stream().
                map(MaterialRow::build).collect(Collectors.toList());
    }

    /**
     * 查找退料列表
     * @param code
     * @return
     */
    public List<MaterialBackRow> materialBacks(String code){
        String point = qrcodeService.valueByCode(code, Constants.CODE_TYPE_LOCATION);
        List<MaterialBackRow> rows = null;
        Map<String, Object> params = new HashMap<>();
        if(StringUtils.isNotNull(point)){
            // 如果是站点码根据站点码查询物料列表
            params.put("station", point);
        }else{
            // 否则根据退料编码查询
            params.put("erpInvBillCode", code);
            rows = erpInvReqService.listByReqNo(code).stream().map(MaterialBackRow::build).collect(Collectors.toList());
        }
        // 查找物料列表
        List<MaterialBackRow> materials = materialMapper.findMaterialBacks(params).stream().
                map(MaterialBackRow::build).collect(Collectors.toList());
        if(StringUtils.isNull(rows)){
            return materials;
        }else if(!materials.isEmpty()){
            Map<String, BigDecimal> map = materials.stream().
                    collect(Collectors.toMap(new Function<MaterialBackRow, String>() {
                        public String apply(MaterialBackRow item) {
                            return item.getSeqNo() + item.getItemCode() + item.getErpInvBillCode();
                        }
                    }, MaterialBackRow::getItemQty));
            rows.stream().map(item -> {
                String key = item.getSeqNo() + item.getItemCode() + item.getErpInvBillCode();
                if(map.containsKey(key)){
                    BigDecimal qty = item.getItemQty().subtract(map.get(key));
                    item.setItemQty(qty.compareTo(BigDecimal.ZERO) <= 0 ? BigDecimal.ZERO : qty);
                }
                return item;
            });
        }
        return rows;
    }

    /**
     * 绑定物料
     * @param param
     */
    @Insert
    @Transactional
    public void bind(MaterialBackSave param) throws MessageException{
        // 校验请求数据
        if (StringUtils.isNull(param.getMaterialBackRows()) || param.getMaterialBackRows().isEmpty()) {
            throw new MessageException("没有退库的物料数据，请重新绑定");
        }
        // 获取站点信息
        String station = qrcodeService.valueByCode(param.getStation(), Constants.CODE_TYPE_LOCATION);
        Map<String, Object> params = new HashMap<>();
        params.put("code", station);
        List<Material> materials = materialMapper.finalMaterials(params);
        if(StringUtils.isNotNull(materials) && !materials.isEmpty()){
            throw new MessageException("站点已经绑定其他退库物料，不能重复绑定");
        }
        // 创建托盘和拣配单
        PickRow pickRow = materialPickService.createContainer(PickSave.build(param, Constants.PICK_STATE_SUCCESS));
        //获取退料类型
        String type = configService.valueByType(Constants.LOCATION_WC_CODE_TL_TYPE);
        // 回写ERP任务流向表 根据领料单号查询如果存在更新否则新增
        erpInvbillService.save(ErpInvBillSave.build(param, type));
        // 添加拣配物料
        pickDetailService.saveBatch(param.getMaterialBackRows().stream().map(item -> PickDetail.build(param, item, pickRow.getId())).
                collect(Collectors.toList()));
        // 添加库存物料
        inventoryDetailService.saveBatch(param.getMaterialBackRows().stream().
                map(item -> InventoryDetail.build(param, item)).collect(Collectors.toList()));
    }

    /**
     * 解绑物料
     * @param station
     * @throws MessageException
     */
    @Transactional
    public void unbind(String station) throws MessageException{
        UserBean userBean = userUtils.getUserInfo();
        String point = qrcodeService.valueByCode(station, Constants.CODE_TYPE_LOCATION);
        if(StringUtils.isNull(point)){
            throw new MessageException("站点不正确");
        }
        Map<String, Object> params = new HashMap<>();
        params.put("code", point);
        List<Material> materials = materialMapper.finalMaterials(params);
        if(StringUtils.isNull(materials) || materials.isEmpty()){
            throw new MessageException("站点不存在绑定的物料");
        }
        // 拣配单id
        String pickId = materials.get(0).getPickId();
        // 所有托盘编号
        List<String> containers = materials.stream().map(Material::getContainer).collect(Collectors.toList());
        // 删除拣配单
        pickService.remove(new LambdaQueryWrapper<Pick>().eq(Pick::getId, pickId));
        // 删除托盘
        pickContainerService.remove(new LambdaQueryWrapper<PickContainer>().
                eq(PickContainer::getPick, pickId));
        // 删除物料
        pickDetailService.remove(new LambdaQueryWrapper<PickDetail>().
                eq(PickDetail::getPick, pickId));
        // 更新库存主表
        inventoryService.update(Inventory.build("", Constants.CONTAINER_IS_EMPTY_YES, userBean),
                new LambdaQueryWrapper<Inventory>().in(Inventory::getContainer, containers));
        // 删除库存物料
        inventoryDetailService.remove(new LambdaQueryWrapper<InventoryDetail>().
                in(InventoryDetail::getContainer, containers));
    }

}
